import { ipcRenderer } from "electron";
import { router, RouterName } from '@/views/router';
import { SimulateController } from './Controller';
import { SubWinQueryParams, SubWinName, SimFrameToSubChannel, WinName, SimSubwinMsgToSimWin, SimSubwinMsgToSimWinData } from "@/engine/types/Win";
import qs from 'querystring';
import * as remote from "@electron/remote";
import { localFile } from "@/util/localFile/LocalFileElectron";
import { IpcMsg } from "./types/Ipc";
import { UIOpenNotificationData } from "./types/Socket";
import { HiddenStatus } from "./types/Controller";
import { SimulateStatusType } from "./_";
import { ChartSubType } from "./types/charts";

export default class WinService {

  controller: SimulateController

  subWins: {id: number, name: SubWinName, params?: {[key: string]: string}}[] = []
  framesData: UIOpenNotificationData[] = [];
  mountedSubWins = 0
  closeExceptWins = [SubWinName.ExportActPinData]

  constructor(controller: SimulateController) {
    this.controller = controller;
  }

  serviceInit() {
    this.framesData.length = 0;
    this.mountedSubWins = 0;
    this.closeSubWins();
    this.closeExceptWins = [SubWinName.ExportActPinData];
  }

  getSubWinsByName(name: SubWinName) {
    return this.subWins.filter(w => w.name === name);
  }

  sendInfoToSubWins(info: { type: SimFrameToSubChannel, data?: any }, name?: SubWinName) {
    const aimedWin = name
      ? this.getSubWinsByName(name)
      : this.subWins;
    if (aimedWin.length) {
      for (const win of aimedWin) {
        const frame = remote.BrowserWindow.fromId(Number(win.id));
        if (frame && !frame.isDestroyed()) {
          frame.webContents.send(info.type, info.data);
        }
      }
    }
  }

  closeSubWins(except: SubWinName[] = []) {
    for (const swin of this.subWins) {
      if (!except.includes(swin.name)) {
        const win = remote.BrowserWindow.fromId(Number(swin.id));
        win?.close();
      }
    }
    this.subWins = this.subWins.filter(win => except.includes(win.name));
  }

  async openPluginSubWin(
    pluginRouter: RouterName,
    option: { height: number, width: number, skipTaskbar: boolean, title: SubWinName },
    urlParams?: {}
  ) {
    if (router.hasRoute(pluginRouter)) {
      const path = require('path');
      let winUrl = path.join(__dirname, "index.html");
      if (process.env.NODE_ENV === "development") {
        winUrl = path.join("http://localhost:8199/", "index.html");
      }
      const queryStr = qs.stringify(urlParams);
      winUrl = `${winUrl}?winname=${option.title}&NODE_PORT=${app.getNodeServerPort()}&${queryStr}#/${pluginRouter}`;
      const winId = (await ipcRenderer.invoke("PluginCreateSubWindow", option, winUrl)).data;
      this.subWins.push({ id: winId, name: option.title, params: urlParams });
    } else {
      console.error("router's name is invalidated");
    }
  }

  getQueryParams() {
    const querystring = require("querystring");
    let param: {[props:string]: string} = {};
    if (window.location.search) {
      param = { ...querystring.parse(window.location.search.substring(1)) };
    }
    return param;
  }

  recordQueryParams(p?: SubWinQueryParams) {
    const querystring = require("querystring");
    let param: SubWinQueryParams;
    if (p) {
      param = p;
    } else {
      param = { ...querystring.parse(window.location.search.substring(1)) };
    }
    console.log("location url params: ", param);
    const keys = Object.keys(param);
    if (keys.length) {
      for (const i of keys) {
        // ?? black box
        (this.controller as any)[i] = (param as any)[i];
      }
    }
    return param;
  }

  async chooseSavePath(title: string, defaultPath: string) {
    const extension = 'doc';
    const dialogRes = await localFile.chooseSaveFilePath({
      title,
      filters: [{
        name: "M-Design SimPlugin",
        extensions: [extension]
      }],
      defaultPath,
    });
    return dialogRes.filePath;
  }

  getSimulationWin() { // when sim-win has child this can be used
    const wins = remote.BrowserWindow.getAllWindows();
    for (const win of wins) {
      if (win.title === WinName.Simulation && win.getChildWindows().length) {
        return win;
      }
    }
  }

  simSubWinSendInfoToSimWin(data: SimSubwinMsgToSimWinData) {
    const simW = this.getSimulationWin();
    if (simW) {
      simW.webContents.send(IpcMsg.SimSubwinMsgToSimWin, data);
    } else {
      console.error('no sim-win find');
    }
  }

  async dealFramesData() {
    const openFramePromises = [];
    for (const notification of this.framesData) {
      const configUIModelInfo = (await this.controller.modelApi.modelInfo({
        projectId: this.controller.projectId,
        modelId: notification.uiId })
      ).data?.data;
      console.log(configUIModelInfo, "configUIModelInfo");
      if (!configUIModelInfo) continue;
      switch (configUIModelInfo.baseSt) {
        case 'UIPrototyping::Frame':
          if (configUIModelInfo.hiddenStatus !== HiddenStatus.HIDDEN_IN_ENCAP) {
            openFramePromises.push(this.controller.simUIService.subWinOpen(notification));
          }
          break;
        case 'Simulation::TimeSeriesChart':
          openFramePromises.push(this.controller.chartsService.openChartWin(notification));
          break;
        case 'Simulation::ImageSwitcher':
          openFramePromises.push(this.controller.imageSwitcherService.subWinOpen({
            projectId: this.controller.projectId,
            uiId: notification.uiId,
            instanceId: notification.instanceId,
            sessionId: this.controller.sessionId
          }));
          break;
        case "Simulation::TimelineChart":
          openFramePromises.push(this.controller.chartsService.timeLineService.openChartWin(notification));
          break;
        default:
      }
    }
    if (this.controller.simulationConfig.autoStart) {
      Promise.all(openFramePromises)
        .then(() => {
          this.controller.toolbarService.startSimulation();
        });
    }
  }

  async checkAllSubWinMounted() {
    if (!this.framesData.length) return;
    this.controller.toolbarService.statusChange = SimulateStatusType.checking;
    await new Promise((resolve) => {
      let records = 0;
      let checkInterval = setInterval(() => {
        records++;
        if (this.mountedSubWins === this.framesData.length || records >= 10) {
          clearInterval(checkInterval);
          resolve(true);
        }
      }, 300);
    });
  }
}
